package com.wlyuan.open.scanner.repository.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.wlyuan.core.domain.valueobj.UserId;
import com.wlyuan.open.constants.CarrierTypeEnum;
import com.wlyuan.open.scanner.application.factory.SyncFactory;
import com.wlyuan.open.scanner.assembler.ScannerCarrierAssembler;
import com.wlyuan.open.scanner.config.GroupProperties;
import com.wlyuan.open.scanner.constant.AddressTypeEnum;
import com.wlyuan.open.scanner.dao.entity.SupplierDO;
import com.wlyuan.open.scanner.dao.entity.SymbolDO;
import com.wlyuan.open.scanner.dao.mapper.CompanyMapper;
import com.wlyuan.open.scanner.dao.mapper.SupplierMapper;
import com.wlyuan.open.scanner.dao.mapper.SymbolMapper;
import com.wlyuan.open.scanner.domain.carrier.Carrier;
import com.wlyuan.open.scanner.domain.carrier.CarrierConvert;
import com.wlyuan.open.scanner.repository.AddressRepository;
import com.wlyuan.open.scanner.repository.CarrierRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author lijing
 * @description
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class CarrierRepositoryImpl implements CarrierRepository {
    private final SymbolMapper symbolMapper;
    private final SupplierMapper supplierMapper;
    private final AddressRepository addressRepository;
    private final SyncFactory syncFactory;
    private final GroupProperties groupProperties;
    private final CompanyMapper companyMapper;

    @Override
    public List<Carrier> getList() {
        List<Carrier> result = new ArrayList<>();
        var offline = offline();
        if (!CollectionUtils.isEmpty(offline)) {
            result.addAll(offline);
        }
        var online = online();
        if (!CollectionUtils.isEmpty(online)) {
            result.addAll(online);
        }
        logger.info("承运方数据量：{}", result.size());
        return result;
    }

    @Override
    public Carrier getOffline(Long offlineId) {
        return Optional.ofNullable(offlineId).map(id -> {
            var offline = symbolMapper.getById(id);
            return Optional.ofNullable(offline).map(o -> {
                var addressMap = addressRepository.getAddress(id, AddressTypeEnum.OFFLINE_CARRIER.getValue());
                o.setStationList(addressMap.get(id));
                var carrier = CarrierConvert.convertOffline(o);
                process(carrier);
                return carrier;
            }).orElse(null);
        }).orElse(null);
    }

    @Override
    public List<Long> getOfflineByTime(String startTime, String endTime) {
        return symbolMapper.getByTime(startTime, endTime);
    }

    @Override
    public List<Long> getOfflineByTenantIdTime(Long tenantId, String startTime, String endTime) {
        return symbolMapper.getByTenantIdTime(tenantId, startTime, endTime);
    }

    @Override
    public void getOfflineTenantId(Long tenantId) {
        Optional.ofNullable(tenantId).ifPresent(id -> {
            var offline = symbolMapper.getByTenantId(id);
            if (CollectionUtils.isEmpty(offline)) {
                logger.info("根据租户{}查询线下承运方数据为0", id);
                return;
            }
            logger.info("根据租户{}查询线下承运方数据为{}", tenantId, offline.size());
            offline.forEach(o -> {
                var addressMap = addressRepository.getAddress(o.getSymbolId(), AddressTypeEnum.OFFLINE_CARRIER.getValue());
                o.setStationList(addressMap.get(o.getSymbolId()));
                var carrier = CarrierConvert.convertOffline(o);
                process(carrier);
                syncFactory.sync(ScannerCarrierAssembler.assemble(carrier));
            });
        });
    }

    @Override
    public Carrier getOnline(Long onlineId) {
        return Optional.ofNullable(onlineId).map(id -> {
            var online = supplierMapper.getById(id);
            return Optional.ofNullable(online).map(o -> {
                var addressMap = addressRepository.getAddress(id, AddressTypeEnum.ONLINE_CARRIER.getValue());
                o.setStationList(addressMap.get(id));
                var carrier = CarrierConvert.convertOnline(o);
                process(carrier);
                return carrier;
            }).orElse(null);
        }).orElse(null);
    }

    @Override
    public List<Long> getOnlineByTime(String startTime, String endTime) {
        return supplierMapper.getByTime(startTime, endTime);
    }

    @Override
    public List<Long> getOnlineTenantIdByTime(Long tenantId, String startTime, String endTime) {
        return supplierMapper.getByTenantIdTime(tenantId, startTime, endTime);
    }

    @Override
    public Carrier getOnlineById(Long onlineId) {
        return Optional.ofNullable(onlineId).map(id -> {
            var online = supplierMapper.getById(id);
            return Optional.ofNullable(online).map(o -> {
                var carrier = CarrierConvert.convertOnline(o);
                process(carrier);
                return carrier;
            }).orElse(null);
        }).orElse(null);
    }

    @Override
    public Carrier getOfflineById(Long offlineId) {
        return Optional.ofNullable(offlineId).map(id -> {
            var offline = symbolMapper.getById(id);
            return Optional.ofNullable(offline).map(o -> {
                var carrier = CarrierConvert.convertOffline(o);
                process(carrier);
                return carrier;
            }).orElse(null);
        }).orElse(null);
    }

    @Override
    public Carrier getOnlineByCompanyId(Long ownerCompanyId, Long companyId) {
        return Optional.ofNullable(supplierMapper.getCompanyId(ownerCompanyId, companyId)).map(o -> {
            return CarrierConvert.convertOnline(o);
        }).orElse(null);
    }

    @Override
    public void getOnlineTenantId(Long tenantId) {
        Optional.ofNullable(tenantId).ifPresent(id -> {
            var online = supplierMapper.getByTenantId(id);
            if (CollectionUtils.isEmpty(online)) {
                logger.info("根据租户{}查询线上承运方数据为0", id);
                return;
            }
            logger.info("根据租户{}查询线上承运方数据为{}", tenantId, online.size());
            online.forEach(o -> {
                var addressMap = addressRepository.getAddress(o.getSupplierId(), AddressTypeEnum.OFFLINE_CARRIER.getValue());
                o.setStationList(addressMap.get(o.getSupplierId()));
                var carrier = CarrierConvert.convertOnline(o);
                process(carrier);
                syncFactory.sync(ScannerCarrierAssembler.assemble(carrier));
            });
        });
    }

    @Override
    public List<Carrier> offline() {
        logger.info("所属公司id大于0,SymbolType = 2(承运方标记)");
        var list = symbolMapper.list();
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        logger.info("老数据数据量，size：{}", list.size());
        var symbolIds = list.stream().map(SymbolDO::getSymbolId).collect(Collectors.toList());
        var addressMap = addressRepository.getAddressMap(symbolIds, AddressTypeEnum.OFFLINE_CARRIER.getValue());
        list.forEach(data -> data.setStationList(addressMap.get(data.getSymbolId())));
        return CarrierConvert.convertOffline(list);
    }

    @Override
    public List<Carrier> online() {
        logger.info("线上承运方所属公司ID 和 公司ID 不为空，且都大于0");
        var list = supplierMapper.list();
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        logger.info("老数据数据量，size：{}", list.size());
        var supplierIds = list.stream().map(SupplierDO::getSupplierId).collect(Collectors.toList());
        var addressMap = addressRepository.getAddressMap(supplierIds, AddressTypeEnum.ONLINE_CARRIER.getValue());
        list.forEach(data -> data.setStationList(addressMap.get(data.getSupplierId())));
        var result = CarrierConvert.convertOnline(list);
        result.forEach(c -> {
            process(c);
        });
        return result;
    }

    private void process(Carrier carrier) {
        if (CarrierTypeEnum.isOnline(carrier.getType())) {
            Optional.ofNullable(companyMapper.selectById(carrier.getTenantId())).ifPresent(t -> {
                carrier.setTenantName(t.getCompanyName());
            });
        }
        if (groupProperties.groupTenantList().contains(carrier.getTenantId())) {
            carrier.setUpdateBy(new UserId(0L));
            carrier.setCreateBy(new UserId(0L));
        }
    }
}
